package com.pucong.gitee.database.backup.business.unRelational.redis.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.pucong.gitee.database.backup.business.sys.mapper.SysFileMapper;
import com.pucong.gitee.database.backup.business.unRelational.redis.util.ClusterUtil;
import com.pucong.gitee.database.backup.business.unRelational.redis.util.RedisNode;
import com.pucong.gitee.database.backup.common.entity.redis.KeyBean;
import com.pucong.gitee.database.backup.common.entity.redis.RedisConnect;
import com.pucong.gitee.database.backup.common.entity.redis.ZTreeBean;
import com.pucong.gitee.database.backup.common.entity.sys.SysFile;
import com.pucong.gitee.database.backup.common.entity.sys.UserJwt;
import com.pucong.gitee.database.backup.common.selfenum.RedisTreeType;
import com.pucong.gitee.database.backup.configuration.exception.BusinessException;
import com.pucong.gitee.database.backup.utils.UUID;
import com.pucong.gitee.database.backup.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class DataClusterServiceImpl implements DataClusterService {

    @Autowired
    private SysFileMapper sysFileMapper;

    @Autowired
    private AutoRedisConnectService autoRedisConnectService;

    @Override
    public List<RedisNode> nodeInfo(String id) {
        UserJwt loginUser = UserRequest.getLoginUser();
        RedisConnect connect = autoRedisConnectService.getRedisConnect(id);
        List<RedisNode> nodeList = ClusterUtil.getClusterNode(connect);
        return nodeList;
    }

    @Override
    public ZTreeBean treeInit(String id) {
        UserJwt loginUser = UserRequest.getLoginUser();
        RedisConnect connect = autoRedisConnectService.getRedisConnect(id);
        JedisCluster cluster = ClusterUtil.openCulter(connect);
        if (null != cluster) {
            List<RedisNode> nodeList = ClusterUtil.getClusterNode(connect);
            Map<String, RedisNode> masterNode = ClusterUtil.getMasterNode(nodeList);
            Map<String, JedisPool> clusterNodes = cluster.getClusterNodes();
            long total = 0L;
            for (String nk : clusterNodes.keySet()) {
                if (masterNode.keySet().contains(nk)) {
                    Jedis jedis = clusterNodes.get(nk).getResource();
                    total = total + jedis.dbSize();
                }
            }
            ZTreeBean ztreeBean = new ZTreeBean();
            ztreeBean.setId(UUID.uuid());
            ztreeBean.setName("全部集群节点的KEY" + " (" + total + ")");
            ztreeBean.setType(RedisTreeType.key名称);
            ztreeBean.setCount(total);
            ztreeBean.setIndex(0);
            return ztreeBean;
        } else {
            return null;
        }
    }

    @Override
    public ZTreeBean likeInit(String id, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        RedisConnect connect = autoRedisConnectService.getRedisConnect(id);
        JedisCluster cluster = ClusterUtil.openCulter(connect);
        if (null != cluster) {
            if (StringUtils.isBlank(pattern)) {
                pattern = "*";
            }
            List<RedisNode> nodeList = ClusterUtil.getClusterNode(connect);
            Map<String, RedisNode> masterNode = ClusterUtil.getMasterNode(nodeList);
            Map<String, JedisPool> clusterNodes = cluster.getClusterNodes();
            long total = 0L;
            for (String nk : clusterNodes.keySet()) {
                if (masterNode.keySet().contains(nk)) {
                    Jedis jedis = clusterNodes.get(nk).getResource();
                    total = total + jedis.keys(pattern).size();
                    jedis.close();
                }
            }
            ZTreeBean ztreeBean = new ZTreeBean();
            ztreeBean.setId(UUID.uuid());
            ztreeBean.setName("全部集群节点的KEY" + " (" + total + ")");
            ztreeBean.setType(RedisTreeType.key名称);
            ztreeBean.setCount(total);
            ztreeBean.setIndex(0);
            return ztreeBean;
        } else {
            return null;
        }
    }

    @Override
    public LinkedList<ZTreeBean> treeData(String id, String pid, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        RedisConnect connect = autoRedisConnectService.getRedisConnect(id);
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (StringUtils.isBlank(pattern)) {
                pattern = "*";
            }
            List<RedisNode> nodeList = ClusterUtil.getClusterNode(connect);
            Map<String, RedisNode> masterNode = ClusterUtil.getMasterNode(nodeList);
            Map<String, JedisPool> clusterNodes = cluster.getClusterNodes();
            List<String> keyList = new LinkedList<>();
            for (String nk : clusterNodes.keySet()) {
                if (masterNode.keySet().contains(nk)) {
                    Jedis jedis = clusterNodes.get(nk).getResource();
                    keyList.addAll(jedis.keys(pattern));
                    jedis.close();
                }
            }
            // 按字母排序
            Collections.sort(keyList);

            LinkedList<ZTreeBean> treeList = new LinkedList<>();
            for (String key : keyList) {
                RedisUtil.groupRecursiveLoad(treeList, key, null, pid);
            }
            return treeList;
        } else {
            return new LinkedList<>();
        }
    }

    @Override
    public KeyBean keysData(String id, String key, String order) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, key)) {
                return ClusterUtil.getKeyInfo(cluster, key, order);
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return null;
        }
    }

    @Override
    public Boolean renameKey(String id, String oldKey, String newKey) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, oldKey)) {
                if (!ClusterUtil.existsKey(cluster, newKey)) {
                    ClusterUtil.renameKey(cluster, oldKey, newKey);
                    return true;
                } else {
                    throw new BusinessException("该KEY已存在");
                }
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean recoveKey(String id, String fileId) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            SysFile sysFile = sysFileMapper.selectById(fileId);
            if (null != sysFile) {
                ClusterUtil.recoveKey(cluster, FileUtil.readFileToString(sysFile.getPath()));
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean backupKey(String id, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        RedisConnect connect = autoRedisConnectService.getRedisConnect(id);
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            List<RedisNode> nodeList = ClusterUtil.getClusterNode(connect);
            Map<String, RedisNode> masterNode = ClusterUtil.getMasterNode(nodeList);
            Map<String, JedisPool> clusterNodes = cluster.getClusterNodes();
            StringBuffer dataBuffer = new StringBuffer("");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
            String fileName = "redisplus-dbdata-" + format.format(new Date()) + ".bak";
            String filePath = ApplicationContextUtil.getUploadPath() + "/" + fileName;
            for (String nk : clusterNodes.keySet()) {
                if (masterNode.keySet().contains(nk)) {
                    Jedis jedis = clusterNodes.get(nk).getResource();
                    dataBuffer.append(ClusterUtil.backupKey(jedis, pattern));
                    jedis.close();
                }
            }
            boolean expFlag = FileUtil.writeStringToFile(filePath, dataBuffer.toString());
            if (expFlag) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean removeKey(String id) {
        UserJwt loginUser = UserRequest.getLoginUser();
        RedisConnect connect = autoRedisConnectService.getRedisConnect(id);
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            List<RedisNode> nodeList = ClusterUtil.getClusterNode(connect);
            Map<String, RedisNode> masterNode = ClusterUtil.getMasterNode(nodeList);
            Map<String, JedisPool> clusterNodes = cluster.getClusterNodes();
            for (String nk : clusterNodes.keySet()) {
                if (masterNode.keySet().contains(nk)) {
                    Jedis jedis = clusterNodes.get(nk).getResource();
                    jedis.flushDB();
                    jedis.close();
                }
            }
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean insertKey(String id, int type, String key, String val, long time, double score) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            //1:set,2:zset,3:list,4:hash,5:string
            switch (type) {
                case 1:
                    ClusterUtil.insertSet(cluster, key, val);
                    break;
                case 2:
                    ClusterUtil.insertZset(cluster, key, val, score);
                    break;
                case 3:
                    ClusterUtil.insertList(cluster, key, val);
                    break;
                case 4:
                    String[] valArray = val.split(":");
                    String mapKey = valArray[0];
                    String mapVal = valArray[1];
                    ClusterUtil.insertHash(cluster, key, mapKey, mapVal);
                    break;
                case 5:
                    cluster.set(key, val);
                    break;
            }
            if (time != -1) {
                ClusterUtil.retimeKey(cluster, key, time);
            }
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean updateVal(String id, String json) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            JSONObject data = JSON.parseObject(json);
            Integer type = data.getInteger("type");
            String key = data.getString("key");
            if (ClusterUtil.existsKey(cluster, key)) {
                //1:set,2:zset,3:list,4:hash
                switch (type) {
                    case 1:
                        String oldVal = data.getString("oldVal");
                        String newVal = data.getString("newVal");
                        ClusterUtil.deleteSet(cluster, key, oldVal);
                        ClusterUtil.insertSet(cluster, key, newVal);
                        break;
                    case 2:
                        String oldZval = data.getString("oldVal");
                        String newZval = data.getString("newVal");
                        Integer score = data.getInteger("score");
                        ClusterUtil.deleteZset(cluster, key, oldZval);
                        ClusterUtil.insertZset(cluster, key, newZval, score);
                        break;
                    case 3:
                        Integer itemIndex = data.getInteger("itemIndex");
                        String val = data.getString("val");
                        ClusterUtil.updateList(cluster, key, itemIndex, val);
                        break;
                    case 4:
                        String oldMapKey = data.getString("oldKey");
                        String newMapKey = data.getString("newKey");
                        String newMapVal = data.getString("newVal");
                        ClusterUtil.deleteHash(cluster, key, oldMapKey);
                        ClusterUtil.insertHash(cluster, key, newMapKey, newMapVal);
                        break;
                }
                return true;
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean deleteVal(String id, int type, String key, String val) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, key)) {
                //1:set,2:zset,3:list,4:hash
                switch (type) {
                    case 1:
                        ClusterUtil.deleteSet(cluster, key, val);
                        break;
                    case 2:
                        ClusterUtil.deleteZset(cluster, key, val);
                        break;
                    case 3:
                        long keyIndex = Long.parseLong(val);
                        ClusterUtil.deleteList(cluster, key, keyIndex);
                        break;
                    case 4:
                        String mapKey = val;
                        ClusterUtil.deleteHash(cluster, key, mapKey);
                        break;
                }
                return true;
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean insertVal(String id, int type, String key, String val, double score) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, key)) {
                //1:set,2:zset,3:list,4:hash
                switch (type) {
                    case 1:
                        ClusterUtil.insertSet(cluster, key, val);
                        break;
                    case 2:
                        ClusterUtil.insertZset(cluster, key, val, score);
                        break;
                    case 3:
                        ClusterUtil.insertList(cluster, key, val);
                        break;
                    case 4:
                        String[] valArray = val.split(":");
                        String mapKey = valArray[0];
                        String mapVal = valArray[1];
                        ClusterUtil.insertHash(cluster, key, mapKey, mapVal);
                        break;
                }
                return true;
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean updateStr(String id, String key, String val) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, key)) {
                ClusterUtil.updateStr(cluster, key, val);
                return true;
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean retimeKey(String id, String key, long time) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, key)) {
                ClusterUtil.retimeKey(cluster, key, time);
                return true;
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }

    @Override
    public Boolean deleteKey(String id, String id1, String key) {
        UserJwt loginUser = UserRequest.getLoginUser();
        JedisCluster cluster = autoRedisConnectService.getJedisCluster(id);
        if (null != cluster) {
            if (ClusterUtil.existsKey(cluster, key)) {
                ClusterUtil.deleteKey(cluster, key);
                return true;
            } else {
                throw new BusinessException("该key不存在");
            }
        } else {
            return false;
        }
    }
}
